import gymnasium as gym
import numpy as np
from PIL import Image, ImageDraw


# observation speed. Shouldn't be more than 15, as
# rewarder thread on the server side will fall behind.
FPS = 5

# Area of interest
# miniwob有效区域的大小
WIDTH = 160
HEIGHT = 210
# 有效区域的起始坐标
X_OFS = 10
Y_OFS = 75

# 定义有效观察区域大小
WOB_SHAPE = (3, HEIGHT, WIDTH)


def remotes_url(port_ofs=0, hostname='localhost', count=8):
    hosts = ["%s:%d+%d" % (hostname, 5900 + ofs, 15900 + ofs) for ofs in range(port_ofs, port_ofs+count)]
    return "vnc://" + ",".join(hosts)


def configure(env, remotes, fps=FPS):
    '''
    remotes：远程主机地址和端口信息，如果仅填写数字1则代表是本机运行docker

    这可能是指定远程环境实例的参数。例如，在OpenAI's Universe中，可以使用remotes来指定远程Docker容器，这些容器可以运行指定的环境，而不是在本地运行。这样做的一个好处是可以在多个容器/机器上并行运行多个环境实例，从而加快数据收集。

    fps
    这是“每秒帧数”的缩写，用于指定环境的渲染或数据生成速度。

    vnc_kwargs
    VNC（Virtual Network Computing）是一个允许远程控制另一台计算机的图形桌面共享系统。在此上下文中，它可能被用来远程渲染和交互与环境，特别是如果环境是图形密集型的或在远程机器上运行。

    encoding: VNC的编码类型，tight编码通常用于更好的压缩和性能。
    compress_level: 指定VNC的压缩级别。0可能意味着没有压缩或最低级别的压缩。
    fine_quality_level: 控制图像的质量。在这里，100可能代表最高的图像质量。
    subsample_level: 子采样可以减少色度数据来达到更好的压缩，0可能表示没有子采样或最低级别的子采样。
    '''
    env.configure(remotes=remotes, fps=fps, vnc_kwargs={
        'encoding': 'tight', 'compress_level': 0,
        'fine_quality_level': 100, 'subsample_level': 0
    })


def save_obs(obs, file_name, action=None, action_step_pix=10, action_y_ofs=50, transpose=True):
    """
    Save observation from the WoB
    :param obs: single observation (3d)
    :param file_name: image file to save
    :param action: action index to show on image
    :param action_step_pix: discrete step, taken from SoftmaxClickMouse
    :param action_y_ofs: y ofs, taken from SoftmaxClickMouse
    :return:
    """
    if transpose:
        obs = np.transpose(obs, (1, 2, 0))
    img = Image.fromarray(obs)
    if action is not None:
        draw = ImageDraw.Draw(img)
        if isinstance(action, tuple):
            x_ofs, y_ofs = action
            x_ofs -= X_OFS
            y_ofs -= Y_OFS
        else:
            y_ofs = action_y_ofs + (action % 16) * action_step_pix
            x_ofs = (action // 16) * action_step_pix
        half_step = action_step_pix//2
        draw.ellipse((x_ofs-half_step, y_ofs-half_step, x_ofs+half_step, y_ofs+half_step),
                     (0, 0, 255, 128))
    img.save(file_name)
